
#include <glib.h>
#include "xrtcp_util.h"
#include "xcutil.h"



struct rtcp_parser_st{
    const uint8_t * data;
    int length;
    int is_first;
    RTCPParserV2 * v2parser;
};

rtcp_parser_t rtcp_parser_create(){
    rtcp_parser_t parser = (rtcp_parser_t) g_slice_alloc0(sizeof(struct rtcp_parser_st));
    parser->v2parser = new RTCPParserV2(NULL, 0, true);
    return parser;
}

void rtcp_parser_delete(rtcp_parser_t parser){
    if(parser->v2parser){
        delete parser->v2parser;
        parser->v2parser = NULL;
    }
    g_slice_free(struct rtcp_parser_st, parser);
}

int rtcp_parse_first(rtcp_parser_t parser, const uint8_t * data, int length ){
//    if(parser->v2parser){
//        delete parser->v2parser;
//        parser->v2parser = NULL;
//    }
//    
//    parser->is_first = 1;
//    parser->data = data;
//    parser->length = length;
//    parser->v2parser = new RTCPParserV2(parser->data, parser->length, true);
//    return parser->v2parser->Begin();
    
    return parser->v2parser->parse(data, length);
    
}

int rtcp_parse_next_item(rtcp_parser_t  parser){
    return parser->v2parser->Iterate();
}

int rtcp_parse_next_packet(rtcp_parser_t  parser){
    return parser->v2parser->nextBlock();
}

const RtcpCommonHeader * rtcp_get_header(rtcp_parser_t parser){
    if(!parser->v2parser){
        return NULL;
    }
    return &parser->v2parser->Header();
}

const RTCPPacket * rtcp_get_body(rtcp_parser_t parser){
    if(!parser->v2parser){
        return NULL;
    }
    return &parser->v2parser->Packet();
}

TransportFeedback* rtcp_get_transport_feedback(rtcp_parser_t parser) {
    if(!parser->v2parser){
        return NULL;
    }
    return parser->v2parser->TransportFeedback();
}


#if 0


#include "xrtcp_util.h"
#include "xcutil.h"

#include <assert.h>
#include <math.h>   // ceil
#include <string.h> // memcpy


#define rtcp_header_block_size(x) (kHeaderSizeBytes + (x)->payload_size_bytes + (x)->padding_bytes)

enum ParseState {
    State_TopLevel,            // Top level packet
    State_ReportBlockItem,     // SR/RR report block
    State_SDESChunk,           // SDES chunk
    State_BYEItem,             // BYE item
    State_ExtendedJitterItem,  // Extended jitter report item
    State_RTPFB_NACKItem,      // NACK FCI item
    State_RTPFB_TMMBRItem,     // TMMBR FCI item
    State_RTPFB_TMMBNItem,     // TMMBN FCI item
    State_PSFB_SLIItem,        // SLI FCI item
    State_PSFB_RPSIItem,       // RPSI FCI item
    State_PSFB_FIRItem,        // FIR FCI item
    State_PSFB_AppItem,        // Application specific FCI item
    State_PSFB_REMBItem,       // Application specific REMB item
    State_XRItem,
    State_XR_DLLRItem,
    State_AppItem
};

enum RTCPPT : uint8_t {
    PT_IJ = 195,
    PT_SR = 200,
    PT_RR = 201,
    PT_SDES = 202,
    PT_BYE = 203,
    PT_APP = 204,
    PT_RTPFB = 205,
    PT_PSFB = 206,
    PT_XR = 207
};


static
int RtcpParseCommonHeader(const uint8_t* packet,
                                        size_t size_bytes,
                                        RtcpCommonHeader* parsed_header) {
    if (size_bytes < kHeaderSizeBytes) {
        return -10;
    }
    
    unsigned char v =  (packet[0]>>6) & 0x3;
//    unsigned char p =  (packet[0]>>5) & 0x1;
    unsigned char rc = (packet[0]>>0) & 0x1F;
    unsigned char packet_type = (packet[1]>>0) & 0xFF;
    unsigned short packet_size_words = be_get_u16(packet+2); // packet length in 4bytes minus 1
    bool has_padding = (packet[0] & 0x20) != 0;
    
    const uint8_t kRtcpVersion = 2;
    if (v != kRtcpVersion) {
        return -20;
    }
    
    
    if (size_bytes < packet_size_words * 4) {
        return -30;
    }
    
    size_t payload_size = packet_size_words * 4;
    size_t padding_bytes = 0;
    if (has_padding) {
        if (payload_size <= kHeaderSizeBytes) {
            return -40;
        }
        
        padding_bytes = packet[payload_size - 1];
        if ((kHeaderSizeBytes + padding_bytes) > payload_size) {
            return -50;
        }
        payload_size -= padding_bytes;
    }
    payload_size -= kHeaderSizeBytes;
    
    parsed_header->version = kRtcpVersion;
    parsed_header->count_or_format = rc;
    parsed_header->packet_type = packet_type;
    parsed_header->payload_size_bytes = payload_size;
    parsed_header->padding_bytes = padding_bytes;
    
    return 0;
}

static inline
void EndCurrentBlock(RtcpParser * parser)
{
    parser->_ptrRTCPData = parser->_ptrRTCPBlockEnd;
}


static
int ParseSR(RtcpParser * parser){
    const ptrdiff_t length = parser->_ptrRTCPBlockEnd - parser->_ptrRTCPData;
    
    if (length < 28)
    {
        EndCurrentBlock(parser);
        return -1;
    }
    
    parser->_ptrRTCPData += 4; // Skip header
    
    parser->_packetType = RTCPPacketTypes::kSr;
    
    parser->_packet.SR.SenderSSRC = *parser->_ptrRTCPData++ << 24;
    parser->_packet.SR.SenderSSRC += *parser->_ptrRTCPData++ << 16;
    parser->_packet.SR.SenderSSRC += *parser->_ptrRTCPData++ << 8;
    parser->_packet.SR.SenderSSRC += *parser->_ptrRTCPData++;
    
    parser->_packet.SR.NTPMostSignificant = *parser->_ptrRTCPData++ << 24;
    parser->_packet.SR.NTPMostSignificant += *parser->_ptrRTCPData++ << 16;
    parser->_packet.SR.NTPMostSignificant += *parser->_ptrRTCPData++ << 8;
    parser->_packet.SR.NTPMostSignificant += *parser->_ptrRTCPData++;
    
    parser->_packet.SR.NTPLeastSignificant = *parser->_ptrRTCPData++ << 24;
    parser->_packet.SR.NTPLeastSignificant += *parser->_ptrRTCPData++ << 16;
    parser->_packet.SR.NTPLeastSignificant += *parser->_ptrRTCPData++ << 8;
    parser->_packet.SR.NTPLeastSignificant += *parser->_ptrRTCPData++;
    
    parser->_packet.SR.RTPTimestamp = *parser->_ptrRTCPData++ << 24;
    parser->_packet.SR.RTPTimestamp += *parser->_ptrRTCPData++ << 16;
    parser->_packet.SR.RTPTimestamp += *parser->_ptrRTCPData++ << 8;
    parser->_packet.SR.RTPTimestamp += *parser->_ptrRTCPData++;
    
    parser->_packet.SR.SenderPacketCount = *parser->_ptrRTCPData++ << 24;
    parser->_packet.SR.SenderPacketCount += *parser->_ptrRTCPData++ << 16;
    parser->_packet.SR.SenderPacketCount += *parser->_ptrRTCPData++ << 8;
    parser->_packet.SR.SenderPacketCount += *parser->_ptrRTCPData++;
    
    parser->_packet.SR.SenderOctetCount = *parser->_ptrRTCPData++ << 24;
    parser->_packet.SR.SenderOctetCount += *parser->_ptrRTCPData++ << 16;
    parser->_packet.SR.SenderOctetCount += *parser->_ptrRTCPData++ << 8;
    parser->_packet.SR.SenderOctetCount += *parser->_ptrRTCPData++;
    
    parser->_packet.SR.NumberOfReportBlocks = parser->_numberOfBlocks;
    
    // State transition
    if(parser->_numberOfBlocks != 0)
    {
        parser->_state = ParseState::State_ReportBlockItem;
    }else
    {
        // don't go to state report block item if 0 report blocks
        parser->_state = ParseState::State_TopLevel;
        EndCurrentBlock(parser);
    }
    return 0;
    
}

static
void IterateTopLevel(RtcpParser * parser)
{
    for (;;)
    {
        if (parser->_ptrRTCPDataEnd <= parser->_ptrRTCPData)
            return;
        
        if (!RtcpParseCommonHeader(parser->_ptrRTCPData, parser->_ptrRTCPDataEnd - parser->_ptrRTCPData,
                                   &parser->header)) {
            return;
        }
        parser->_ptrRTCPBlockEnd = parser->_ptrRTCPData + rtcp_header_block_size(&parser->header);;
        if (parser->_ptrRTCPBlockEnd > parser->_ptrRTCPDataEnd)
        {
            ++parser->num_skipped_blocks_;
            return;
        }
        
        switch (parser->header.packet_type) {
            case PT_SR:
            {
                // number of Report blocks
                parser->_numberOfBlocks = parser->header.count_or_format;
                ParseSR(parser);
                return;
            }
//            case PT_RR:
//            {
//                // number of Report blocks
//                _numberOfBlocks = header.count_or_format;
//                ParseRR();
//                return;
//            }
//            case PT_SDES:
//            {
//                // number of SDES blocks
//                _numberOfBlocks = header.count_or_format;
//                const bool ok = ParseSDES();
//                if (!ok)
//                {
//                    // Nothing supported found, continue to next block!
//                    break;
//                }
//                return;
//            }
//            case PT_BYE:
//            {
//                _numberOfBlocks = header.count_or_format;
//                const bool ok = ParseBYE();
//                if (!ok)
//                {
//                    // Nothing supported found, continue to next block!
//                    break;
//                }
//                return;
//            }
//            case PT_IJ:
//            {
//                // number of Report blocks
//                _numberOfBlocks = header.count_or_format;
//                ParseIJ();
//                return;
//            }
//            case PT_RTPFB:
//                FALLTHROUGH();
//            case PT_PSFB:
//            {
//                if (!ParseFBCommon(header)) {
//                    // Nothing supported found, continue to next block!
//                    break;
//                }
//                return;
//            }
//            case PT_APP:
//            {
//                const bool ok = ParseAPP(header);
//                if (!ok)
//                {
//                    // Nothing supported found, continue to next block!
//                    break;
//                }
//                return;
//            }
//            case PT_XR:
//            {
//                const bool ok = ParseXr();
//                if (!ok)
//                {
//                    // Nothing supported found, continue to next block!
//                    break;
//                }
//                return;
//            }
            default:
                // Not supported! Skip!
                ++parser->num_skipped_blocks_;
                EndCurrentBlock(parser);
                break;
        }
    }
}

int rtcp_parse_first(const uint8_t * data, int length, RtcpParser * parser ){
    int ret = -1;
    do{
        memset(parser, 0, sizeof(RtcpParser));
        parser->_ptrRTCPDataBegin = data;
        parser->_ptrRTCPDataEnd = data+length;
        parser->_ptrRTCPData = data;
        parser->_packetType = RTCPPacketTypes::kInvalid;
        parser->_state = ParseState::State_TopLevel;
        ret = 0;
    }while(0);
    return ret;
}


int rtcp_parse_next(RtcpParser * parser){
    
    // Reset packet type
    parser->_packetType = RTCPPacketTypes::kInvalid;
    if(!parser->_validPacket){
        return parser->_packetType;
    }
    
    switch (parser->_state)
    {
        case ParseState::State_TopLevel:
            IterateTopLevel(parser);
            break;
//        case ParseState::State_ReportBlockItem:
//            IterateReportBlockItem();
//            break;
//        case ParseState::State_SDESChunk:
//            IterateSDESChunk();
//            break;
//        case ParseState::State_BYEItem:
//            IterateBYEItem();
//            break;
//        case ParseState::State_ExtendedJitterItem:
//            IterateExtendedJitterItem();
//            break;
//        case ParseState::State_RTPFB_NACKItem:
//            IterateNACKItem();
//            break;
//        case ParseState::State_RTPFB_TMMBRItem:
//            IterateTMMBRItem();
//            break;
//        case ParseState::State_RTPFB_TMMBNItem:
//            IterateTMMBNItem();
//            break;
//        case ParseState::State_PSFB_SLIItem:
//            IterateSLIItem();
//            break;
//        case ParseState::State_PSFB_RPSIItem:
//            IterateRPSIItem();
//            break;
//        case ParseState::State_PSFB_FIRItem:
//            IterateFIRItem();
//            break;
//        case ParseState::State_PSFB_AppItem:
//            IteratePsfbAppItem();
//            break;
//        case ParseState::State_PSFB_REMBItem:
//            IteratePsfbREMBItem();
//            break;
//        case ParseState::State_XRItem:
//            IterateXrItem();
//            break;
//        case ParseState::State_XR_DLLRItem:
//            IterateXrDlrrItem();
//            break;
//        case ParseState::State_AppItem:
//            IterateAppItem();
//            break;
        default:
//            gdbge("Invalid state!");
            break;
    }
    return parser->_packetType;

}



#endif

